import json
import os
from datetime import datetime
from decimal import Decimal

from alipay import AliPay
from django import http
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection
from apps.areas.models import Address
from apps.goods.models import SKU

#订单,提供订单页面,返回订单页面所需商品数据
from apps.orders.models import OrderInfo,OrderGoods, Payment
from utils.response_code import RETCODE

class OrderView(LoginRequiredMixin, View):

    def get(self,request):
        ''''''
        '''所需参数 addresses,skus,total_count,total_amout,freight,payment_amount,defai;t_address_id'''
        try:
            addresses = Address.objects.filter(user=request.user,is_deleted=False)
        except:
            addresses = None  #传给前端会判断,如果为None就会跳转到添加地址页面

        #找出selected为真的商品
        skus = []
        #连接数据库
        client = get_redis_connection('carts')
        #循环遍历所有购物车商品信息
        all_cart_dict = client.hgetall(request.user.id)
        total_count = 0
        total_amount = Decimal(0.00)
        for sku_id,values_dict in all_cart_dict.items():
        #判断selected为true的
            if json.loads(values_dict.decode()).get('selected') == True:

                # 加入skus中
                if sku_id.decode() != 'None':
                    count = json.loads(values_dict.decode()).get('count')
                    total_count += count

                    sku = SKU.objects.get(id = sku_id.decode())
                    total_amount += (count *sku.price)
                    sku.count = count
                    sku.amount = (count *sku.price)
                    skus.append(sku)
        context = {
            'addresses': addresses,
            'skus': skus,  #有商品对象的列表
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': str(Decimal(10.00)),
            'payment_amount': str(total_amount + Decimal(10.00)),  #加个运费的总支付费用
            'default_address_id': request.user.default_address_id #默认地址修改到user中了
        }

        return render(request,'place_order.html',context)


class CommitOrderView(LoginRequiredMixin, View):
    #前端ajax访问(非表单),将订单商品等信息添加进订单表,和商品订单表
    def post(self,request):
        #地址和支付方式由前端返回,因为是用户选择收货的地址,传入的是address_id
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')
        #校验参数
        if not all([address_id, pay_method]):
            return http.HttpResponseForbidden('缺少必传参数')
        #通过address_id获得address
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return http.HttpResponseForbidden('参数address_id错误')

        #生成订单号,和获取表中需要的信息,前端为了安全性并不会给金额总数等信息,需要自己去数据库取
        client = get_redis_connection('carts')
        all_dict = client.hgetall(request.user.id)
        #{b'3': b'{"selected": true, "count": 1}', b'6': b'{"selected": true, "count": 3}', b'None': b'{"selected": true, "count": 4}'}
        total_count =0
        total_amount =0

        '''-----初始化开启事务-----'''
        with transaction.atomic():
            '''-----设置保存点-----'''
            save_id = transaction.savepoint()
            try:
        # 将获取到的信息写入订单mysql数据表中 ,这条记录的对象叫order可以用来动态修改
                order =OrderInfo.objects.create(
                    order_id=datetime.now().strftime('%Y%m%d%H%M%S') + ('%09d' % request.user.id),
                    user = request.user,
                    address = address,
                    total_count =total_count,
                    total_amount =total_amount,
                    freight = Decimal(10.00),
                    pay_method = pay_method,
                    status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY']else
                        OrderInfo.ORDER_STATUS_ENUM['UNSEND'])

                skus_id_list =[]
                for sku_id_byte, values_dict in all_dict.items():
                    if sku_id_byte.decode() != 'None':

                        if json.loads(values_dict.decode()).get('selected') == True:
                            skus_id_list.append(sku_id_byte.decode())
                            sku = SKU.objects.get(id=sku_id_byte.decode())
                            #count是购物车取出的用户选中的要结算的商品数量
                            count = json.loads(values_dict.decode()).get('count')
                            total_count += count
                            total_amount += count * sku.price
                            while True:
                                #下单的时候还需要判断是否有库存
                                if count > sku.stock:
                                    transaction.savepoint_rollback(save_id)
                                    return JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                                '''乐观锁：再次判断一下库存是否还有'''
                                result = SKU.objects.filter(id=sku_id_byte.decode(),stock=sku.stock).update(stock=sku.stock-count,sales=sku.spu.sales+count)
                                #update的方法不用save ，自动保存
                                '''就是用result来严格判断是否写入成功了'''
                                if result == 0:
                                    #如果下单失败但是库存足够则继续循环
                                    continue
                                else:
                                    break

                            #如果有库存,销量增加,库存减少
                            # sku.spu.sales += count
                            # sku.spu.save()
                            # sku.stock -= count
                            # sku.save()

                            #将遍历出来的商品写入外键订单商品表中
                            OrderGoods.objects.create(
                                order=order,
                                sku=sku,
                                count=count,
                                price=sku.price,
                            )
                order.total_count = total_count
                order.total_amount = total_amount
                order.save()
                transaction.savepoint_commit(save_id)
                # 清空购物车已经结算过的商品
                client.hdel(request.user.id, *skus_id_list)
                return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})
            except Exception:
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单失败'})


class CommitSuccessView(LoginRequiredMixin, View):

    def get(self,request):
        #接受参数order_id，payment_amount,pay_method 给成功页面
        context = {
            'order_id':request.GET.get('order_id'),
            'payment_amount':str(request.GET.get('payment_amount')),
            'pay_method':request.GET.get('pay_method'),
        }
        return render(request, 'order_success.html',context)

#支付宝登录支付对接
class PaymentView(LoginRequiredMixin, View):

    def get(self,request,order_id):
        #路径传参用来寻找订单号用

        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,  # 默认回调url
            app_private_key_path=os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "utils/zfb_ssh/app_private_key.pem"),
            alipay_public_key_path=os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))),
                                                "utils/zfb_ssh/alipay_public_key.pem"),
            sign_type="RSA2",
            debug=settings.ALIPAY_DEBUG
        )

        #传递所需的参数,生成支付宝网页

        #参数需要订单状态,从订单信息表中查找, 状态是等待支付的,user,orderid
        try:
            order = OrderInfo.objects.get(order_id=order_id,user=request.user,status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'])
        except Exception:
            return http.HttpResponseForbidden('订单信息错误')
        login_url  = alipay.api_alipay_trade_page_pay(
            out_trade_no=order_id,
            subject="帅多商城_%s"%order_id,
            total_amount= str(order.total_amount),
            return_url=settings.ALIPAY_RETURN_URL,
        )
        #拼接一下所需参数
        #响应登录支付宝连接,参数以路径传参
        alipay_url = settings.ALIPAY_URL +'?'+login_url
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'alipay_url': alipay_url})



#通过实例对象验证支付宝返回签名,写入模型类
class PaymentStatusView(View):

    def get(self,request):
        #获取支付宝返回的全部参数来校验是不是支付宝传给我的参数
        scret_dict = request.GET
        data = scret_dict.dict()
        print(data)
        '''通过校验签名'''
        sign = data.pop('sign')
        print(sign)

        #用实例对象的verify方法来校验
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,  # 默认回调url
            app_private_key_path=os.path.join(
                os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))),
                "utils/zfb_ssh/app_private_key.pem"),
            alipay_public_key_path=os.path.join(
                os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))),
                "utils/zfb_ssh/alipay_public_key.pem"),
            sign_type="RSA2",
            debug=settings.ALIPAY_DEBUG
        )
        success = alipay.verify(data,sign)
        #如果用实例对象验证成功我才写入表中 , 订单号,交易流水号
        print(success)

        if success:
            order_id = data.get('out_trade_no')

            #流水号
            trade_id = data.get('trade_no')
            Payment.objects.create(
                order_id=order_id,
                trade_id=trade_id
            )

            #修改订单状态为带评价
            OrderInfo.objects.filter(order_id=order_id, status=OrderInfo.ORDER_STATUS_ENUM['UNPAID']).update(status=OrderInfo.ORDER_STATUS_ENUM['UNCOMMENT'])

            #返回流水订单号给前端显示
            context ={
                'trade_id':trade_id
            }

            return render(request, 'pay_success.html', context)
        else:
            return http.HttpResponseForbidden('非法请求')



#订单页面
class MyOrdersView(LoginRequiredMixin,View):

    def get(self,request):
        #需要一个trand_id交易订单号,order_id?
        # 需要商品sku_id,去找ordergoods表
        OrderInfo_records = OrderInfo.objects.filter(user=request.user)
        # if not OrderInfo_records:
        #     return http.HttpResponse('没有订单')
        my_dict={}
        #格式 order_id :{'status':'1','skus':skus}
        count = {}
        #根据订单号去找商品
        for record in OrderInfo_records:
            time = record.create_time.strftime('%Y-%m-%d %H:%S:%M')
            total_amount =record.total_amount
            total_count=record.total_count
            freight =record.freight
            skus = []
            values_dict = {}
            #record是订单信息表的一条记录
            order_id = record.order_id
            status =record.status

            #获得所有对应订单id的商品信息
            goods = record.skus.all()
            #遍历sku添加到skus列表
            for good in goods:
                #循环 得到第一个order id 对应的全部商品
                #获得商品
                skus.append(good.sku)
                # count[good.sku_id] = good.count

            values_dict['status']=record.ORDER_STATUS_CHOICES[status-1][1]
            values_dict['skus']=skus
            values_dict['time']=time
            values_dict['total_count']=total_count
            values_dict['freight']=freight
            values_dict['total_amount']=total_amount
            # values_dict['count'] =count

            my_dict[order_id]=values_dict
#{'20190828044432000000001': {'skus': [<SKU: 3: Apple iPhone 8 Plus (A1864) 64GB 金色 移动联通电信4G手机>], 'status': 1}

        context = {
            'my_dict':my_dict,
        }
        return render(request, 'user_center_order.html', context)


#提供评价界面  ,  前端不能接收SKU对象,不能接收数据库中的对象,转成字典啊！
class CommentView(LoginRequiredMixin,View):

    def get(self,request,order_id):
        #一个商品一个评价,需要sku,前端传入满意度和评价,写入订单商品表中
        #此处只需要一个sku,接收前端的skus字典,没有办法通过get传入非字符串,先获取orderid

        goods_infos = OrderGoods.objects.filter(order_id=order_id)
        skus = []
        for good_info in goods_infos:
            sku_id = good_info.sku_id
            #得到sku_id
            sku = SKU.objects.get(id=sku_id)
            skus.append({
                'name': sku.name,
                'price':str(sku.price),
                # 'comment':sku.comments,
                'default_image':sku.default_image.url,
                'sku_id':sku_id,
                'order_id':order_id,
            })


        #渲染
        context = {
           'skus':skus
        }

        return render(request,'goods_judge.html',context)



class DealCommentPageView(LoginRequiredMixin,View):
    # 接收axios参数,写入表中,用订单号和商品sku确定一个商品,修改表中数据,
    #如果遍历订单中的所有商品都已评价, 则修改订单状态为已完成
    def post(self,request):
        #接收参数
        json_dict = json.loads(request.body.decode())

        order_id = json_dict.get('order_id')
        sku_id = json_dict.get('sku_id')
        comment = json_dict.get('comment')
        score = json_dict.get('score')
        is_anonymous = json_dict.get('is_anonymous')

        is_anonymous= 1 if (is_anonymous) else 0
        #写入表中
        try:
            order_good = OrderGoods.objects.get(order_id=order_id,sku_id=sku_id)
            order_good.comment = comment
            order_good.score = score
            order_good.is_commented = True
            order_good.is_anonymous = is_anonymous
            order_good.save()
        except Exception:
            return JsonResponse({'code': '4101'})

        #修改信息表中的订单状态

        #获取一个订单下所有的商品
        order_goods = OrderGoods.objects.filter(order_id=order_id)
        a = 0
        for goods in order_goods:
            if goods.is_commented == False:
                a +=1

        if a==0:#如果全部评价了
            order_info = OrderInfo.objects.get(order_id=order_id,user=request.user)
            order_info.status = 5
            print('到这里了')
            order_info.save()

        return JsonResponse({'code': '0'})




